package com.zkthink.ceres.promotion.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.annotation.SqlParser;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.databind.ser.Serializers;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.zkthink.base.R;
import com.zkthink.base.request.PageParams;
import com.zkthink.base.service.SuperServiceImpl;
import com.zkthink.cache.repository.RedisRepositoryImpl;
import com.zkthink.ceres.pay.service.PayService;
import com.zkthink.ceres.promotion.constants.PromotionConstant;
import com.zkthink.ceres.promotion.dao.PromotionApplyInfoMapper;
import com.zkthink.ceres.promotion.dao.PromotionMapper;
import com.zkthink.ceres.promotion.dao.PromotionProductMapper;
import com.zkthink.ceres.promotion.dto.PromotionApplyInfoPageDTO;
import com.zkthink.ceres.promotion.dto.PromotionIdDTO;
import com.zkthink.ceres.promotion.entity.Promotion;
import com.zkthink.ceres.promotion.entity.PromotionApplyInfo;
import com.zkthink.ceres.promotion.entity.TenantPromotionApplyInfo;
import com.zkthink.ceres.promotion.enums.PromotionAuditStatusEnum;
import com.zkthink.ceres.promotion.service.PromotionApplyInfoService;
import com.zkthink.ceres.promotion.service.PromotionAuditLogService;
import com.zkthink.ceres.promotion.vo.admin.PromotionApplyInfoPageAdminVO;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import com.zkthink.context.BaseContextHandler;
import jodd.util.StringUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;

/**
 * <p>
 * 业务实现类 营销活动申请表
 * </p>
 *
 * @author kellen
 * @date 2020-06-16
 */
@Slf4j
@AllArgsConstructor
@Service
public class PromotionApplyInfoServiceImpl extends
    SuperServiceImpl<PromotionApplyInfoMapper, PromotionApplyInfo> implements
    PromotionApplyInfoService {

  private PromotionMapper promotionMapper;

  private PromotionAuditLogService promotionAuditLogService;

  private PromotionProductMapper promotionProductMapper;

  private RedisRepositoryImpl redisRepository;

  private PayService payService;

  @Override
  public R<Boolean> applyPromotion(PromotionApplyInfo info) {
    try {
      String validateResult = validateApplyPromotion(info);
      if (StringUtils.isNoneBlank(validateResult)) {
        return R.fail(-1, validateResult);
      }

      if (info.getId() != null && info.getId() != 0) {
        PromotionApplyInfo originApplyInfo = baseMapper.selectById(info.getId());
        if (originApplyInfo.getStatus() != PromotionAuditStatusEnum.APPLY_FAIL.getCode()) {
          return R.fail("当前报名状态不是报名失败，无法重新报名");
        }
        originApplyInfo.setProductIds(info.getProductIds());
        baseMapper.updateById(originApplyInfo);
        promotionAuditLogService.addLog(info.getPromotionId(), info.getId(),
            PromotionAuditStatusEnum.AUDITING.getCode(),
            "重新报名");
      } else {
        baseMapper.insert(info);
        promotionAuditLogService.addLog(info.getPromotionId(), info.getId(),
            PromotionAuditStatusEnum.AUDITING.getCode(),
            "首次报名");
      }
    } catch (Exception e) {
      log.error("applyPromotion fail:" + e.getMessage(), e);
      return R.fail(-1, "报名活动失败");
    }
    return R.success(true);
  }

  @Override
  @Transactional
  public R<Boolean> auditPromotion(PromotionApplyInfo info) {
    if (info == null || info.getId() == null || !PromotionAuditStatusEnum.AUDIT_STATUS_LIST
        .contains(info.getStatus())) {
      return R.fail(-1, "参数错误");
    }
    PromotionApplyInfo applyInfo = baseMapper.selectByIdIgnoreTenant(info.getId());
    if (applyInfo == null || applyInfo.getIsDelete() == 1) {
      return R.fail(-1, "该活动报名不存在或已删除");
    }
    if (applyInfo.getStatus() == null || applyInfo.getStatus() != PromotionAuditStatusEnum.AUDITING
        .getCode()) {
      return R.fail(-1, "该活动报名不是待审核状态，不能审核");
    }
    info.setAuditCount(applyInfo.getAuditCount() + 1);
    baseMapper.updateByIdIgnoreTenant(info);
    promotionAuditLogService.addLog(applyInfo.getPromotionId(), info.getId(),
        info.getStatus(),
        info.getAuditRemark());
    return R.success();
  }

  @Override
  public R<IPage<PromotionApplyInfoPageAdminVO>> page(
      PageParams<PromotionApplyInfoPageDTO> params) {
    IPage page = baseMapper.page(params.getPage(), params.getModel());
    List<PromotionApplyInfoPageAdminVO> applyInfoPageAdminVOList = page.getRecords();
    //组装商品数量
    if (!CollectionUtils.isEmpty(applyInfoPageAdminVOList)) {
      applyInfoPageAdminVOList.forEach(e -> {
        int productCount = 0;
        String productIds = e.getProductIds();
        if (StrUtil.isNotBlank(productIds)) {
          productCount = StrUtil.count(productIds, ",") + 1;
        }
        e.setProductCount(productCount);
      });
    }
    return R.success(page);
  }

  @Override
  public R<Boolean> closeApplyInfo(PromotionIdDTO promotionIdDTO) {
    if(promotionIdDTO==null || promotionIdDTO.getId()==null) {
      return R.fail("参数不正确，无法清退活动申请");
    }
    TenantPromotionApplyInfo promotionApplyInfo = baseMapper.selectByIdWithTenant(promotionIdDTO.getId());
    if (promotionApplyInfo == null || promotionApplyInfo.getIsDelete() == 1) {
      return R.fail("活动申请不存在或已删除");
    }
    String productIds = promotionApplyInfo.getProductIds();
    Long promotionId = promotionApplyInfo.getPromotionId();

    //删除活动和商品的关系
    promotionProductMapper.deleteSpecifiedRelation(promotionId,productIds);

    //清空缓存中商品和活动的关联缓存
    for(String productId:productIds.split(",")){
      String key = PromotionConstant.PRODUCT_PROMOTION_RELATION_PREFIX + productId;
      redisRepository.del(key);
    }

    //不需要作废优惠券，因为优惠券是用户和平台的关系，
    // 上一步清除商品和活动的关系后，优惠券不能在这些商品使用，但是可以在别的参加本活动的商品使用

    //修改活动申请的状态
    PromotionApplyInfo updateInfo = new PromotionApplyInfo();
    updateInfo.setId(promotionApplyInfo.getId());
    updateInfo.setStatus(PromotionAuditStatusEnum.CLOSED.getCode());
    baseMapper.updateById(updateInfo);

    //如果有缴纳保证金，退还保证金
    if(StringUtil.isNotBlank(promotionApplyInfo.getPayDepositOrderId())){
      try{

        Promotion promotion = promotionMapper.selectById(promotionId);

        String tenantCode = promotionApplyInfo.getTenantCode();
        String outTradeNo = promotionApplyInfo.getPayDepositOrderId();
        Long applyInfoId = promotionApplyInfo.getId();

        String outRefundNo = DigestUtils.md5DigestAsHex((applyInfoId+"_"+promotionId+"_"+tenantCode).getBytes());

        WxPayRefundRequest refundRequest = new WxPayRefundRequest();
        refundRequest.setOutTradeNo(outTradeNo);
        refundRequest.setOutRefundNo(outRefundNo);
        refundRequest.setTotalFee(promotion.getSecurityDeposit().intValue());
        refundRequest.setRefundFee(promotion.getSecurityDeposit().intValue());
        WxPayRefundResult refundResult = payService.refund(refundRequest);
        log.info("refundResult:"+ JSON.toJSONString(refundResult));
      }catch(Exception e){
        log.error("refund fail:"+e.getMessage(),e);
      }
    }

    //BaseContextHandler.setTenant(currentTenant);
    return R.success();
  }

  /**
   * 校验能否正常报名
   *
   * @author 善泉 2020/6/20 22:28
   */
  private String validateApplyPromotion(PromotionApplyInfo info) {
    if (info == null || info.getPromotionId() == null || StringUtils
        .isBlank(info.getProductIds())) {
      return "报名失败，请输入正确的参数";
    }
    Long promotionId = info.getPromotionId();
    Promotion promotion = promotionMapper.selectById(promotionId);
    if (promotion == null) {
      return "活动不存在，无法报名";
    }
    if (!(promotion.getApplyStartTime() != null && promotion.getApplyStartTime()
        .isBefore(LocalDateTime.now())
        && promotion.getApplyEndTime() != null && promotion.getApplyEndTime()
        .isAfter(LocalDateTime.now()))) {
      return "当前不处于活动报名期间，无法报名";
    }
    return null;
  }

}
